use casbin::prelude::*;
use casbin::{CoreApi, FileAdapter, Filter, Model};
use serde::Deserialize;
use std::fs;

#[derive(Clone, Deserialize, Debug)]
pub struct CasbinConfig {
    model: String,
    policy: String,
}

impl CasbinConfig {
    pub fn is_db(&self) -> bool {
        self.policy.starts_with("mysql")
            || self.policy.starts_with("sqlite")
            || self.policy.starts_with("postgres")
    }

    pub async fn casbin(&self) -> Result<casbin::prelude::Enforcer> {
        let model_str = fs::read_to_string(&self.model).unwrap();
        let m = casbin::DefaultModel::from_str(&model_str).await.unwrap();
        Ok(if self.is_db() {
            let a = seaorm_adapter::SeaOrmAdapter::new(&self.policy)
                .await
                .unwrap();
            casbin::Enforcer::new(m, a).await.unwrap()
        } else {
            casbin::Enforcer::new(m, FileAdapter::new(self.policy.clone()))
                .await
                .unwrap()
        })
    }
}

pub struct EmptyAdapter;

#[axum::async_trait]
impl casbin::Adapter for EmptyAdapter {
    async fn load_policy(&mut self, _m: &mut dyn Model) -> Result<()> {
        Ok(())
    }

    async fn load_filtered_policy<'a>(&mut self, _m: &mut dyn Model, _f: Filter<'a>) -> Result<()> {
        Ok(())
    }

    async fn save_policy(&mut self, _m: &mut dyn Model) -> Result<()> {
        Ok(())
    }

    async fn add_policy(&mut self, _sec: &str, _ptype: &str, _rule: Vec<String>) -> Result<bool> {
        Ok(true)
    }

    async fn add_policies(
        &mut self,
        _sec: &str,
        _ptype: &str,
        _rules: Vec<Vec<String>>,
    ) -> Result<bool> {
        Ok(true)
    }

    async fn remove_policy(&mut self, _sec: &str, _pt: &str, _rule: Vec<String>) -> Result<bool> {
        Ok(true)
    }

    async fn remove_policies(
        &mut self,
        _sec: &str,
        _pt: &str,
        _rules: Vec<Vec<String>>,
    ) -> Result<bool> {
        Ok(true)
    }

    async fn remove_filtered_policy(
        &mut self,
        _sec: &str,
        _pt: &str,
        _field_index: usize,
        _field_values: Vec<String>,
    ) -> Result<bool> {
        Ok(true)
    }

    async fn clear_policy(&mut self) -> Result<()> {
        Ok(())
    }

    fn is_filtered(&self) -> bool {
        false
    }
}
